#ifndef __FLV_SPEC_V10_H__
#define __FLV_SPEC_V10_H__

/* version 1.0 flv specification 
 * flv file format
 */

#include <stdint.h>

#define SIZE_FLV_HEADER 9
#define SIZE_FLV_TAG_HEADER 11

/*
 * flv header
 */
struct flv_header
{
    uint8_t signature[3];// 'F','L','V'         
    uint8_t typeFlagsReserv1:5;
    uint8_t typeFlagsAudio:1;
    uint8_t typeFlagsReserv2:1;
    uint8_t typeFlagsVideo:1;
    uint32_t dataOffset;// size of header,for version 1,always is 9
};

enum flv_tag_type
{
    EFLV_TAG_TYPE_AUDIO = 8,
    EFLV_TAG_TYPE_VIDEO = 9,
    EFLV_TAG_TYPE_SCRIPT = 18,
};

struct flv_tag_header
{
    uint8_t type;
    uint32_t dataSize:24;
    uint32_t timestamp:24;
    uint32_t timestampExt:8;// high byte
    uint32_t streamID:24;// always is 0
};

/**************************** FLV Audio Tag ****************************/
enum flv_audio_format
{// SF = SoundFormat
    EFLV_SF_LPCM_PLAT = 0,// linear pcm,platform endian
    EFLV_SF_ADPCM = 1,
    EFLV_SF_MP3 = 2,
    EFLV_SF_LPCM_LITTLE = 3,// linear pcm ,little endian
    EFLV_SF_NELLYMOSER_16K = 4,
    EFLV_SF_NELLYMOSER_8K = 5,
    EFLV_SF_NELLYMOSER = 6,
    EFLV_SF_G711A_PCM = 7,
    EFLV_SF_G711U_PCM = 8,
    EFLV_SF_RESERVED = 9,
    EFLV_SF_AAC = 10,
    EFLV_SF_SPEEX = 11,
    EFLV_SF_MP3_8K = 14,
    EFLV_SF_DEVICE_SPEC = 15,
};
enum flv_audio_rate
{// SR = SoundRate
    EFLV_SR_5D5KHZ = 0,
    EFLV_SR_11KHZ = 1,
    EFLV_SR_22KHZ = 2,
    EFLV_SR_44KHZ = 3, // for AAC,always is 3
};
enum flv_audio_bits
{// SS = SoundSize
    EFLV_SS_8BIT = 0,
    EFLV_SS_16BIT = 1,
};
enum flv_audio_type
{// ST = SoundType
    EFLV_ST_MONO = 0,
    EFLV_ST_STEREO = 1,
};
struct flv_aac_data
{
    uint8_t packetType; // 0:AAC sequence header, 1:AAC raw data
    union {
	struct AudioSpecificConfig header; // type 0,AudioSpecificConfig see ISO-14496-3.
	uint8_t frameData[320]; // type 1
    }data;
};

struct flv_audio_data
{
    uint8_t format:4;
    uint8_t rate:2; // for AAC,always is 3
    uint8_t bits:1; // 
    uint8_t type:1;// for AAC,always is 1 
    uint8_t payload[]; // for AAC, see @AACAUDIODATA struct
};

/**************************** FLV Video Tag ****************************/
enum flv_video_frametype
{
    EFLV_VFT_KEYFRAME = 1,// for AVC,I frame
    EFLV_VFT_INTERFRAME = 2,// for AVC,P frame
    EFLV_VFT_DISP_INTERFRAME = 3,// H.263 only
    EFLV_VFT_GENERATED_KEYFRAME = 4,
    EFLV_VFT_INFO = 5,
};

enum flv_video_codecid
{
    EFLV_VCID_JPEG = 1,
    EFLV_VCID_SORENSON_H263 = 2,
    EFLV_VCID_SCREEN_VIDEO = 3,
    EFLV_VCID_ON2_VP6 = 4,
    EFLV_VCID_ON2_VP6_ALPHA = 5,
    EFLV_VCID_SCREEN_VIDEO_V2 = 6,
    EFLV_VCID_AVC = 7,
};
struct flv_avc_packet
{
    uint8_t type;// 0:avc sequence header,1:AVC NALU,2:avc end of sequence

    /* 
     * See ISO 14496-12, 8.15.3 for an explanation of composition times 
     * The offset in an FLV file is always in milliseconds.
     */
    int32_t compositionTime:24;// cts = pts,if type is 1 cts offset,else 0

    /*
     * if AVCPacketType == 0
     *	AVCDecoderConfigurationRecord(See ISO 14496-15, 5.2.4.1 for the description)
     * else if AVCPacketType == 1
     *	One or more NALUs (can be individual
     *	slices per FLV packets; that is, full frames
     *	are not strictly required)
     * else if AVCPacketType == 2
     *	Empty
     */
    uint8_t data[];
};

struct flv_video_data
{
    uint8_t frameType:4;
    uint8_t codecID:4;
    uint8_t payload[]; // for avc,see AVCVIDEOPACKET
};

/**************************** FLV Data Tags ****************************/
enum flv_script_vartype
{
    EFLV_VAR_TYPE_DOUBLE = 0, // 8bytes,big endian
    EFLV_VAR_TYPE_BOOL = 1,// 1 byte, 1:true, 0:false
    EFLV_VAR_TYPE_STRING = 2, // see @struct flv_script_string
    EFLV_VAR_TYPE_OBJECT = 3,// see @struct flv_script_object[n]
    EFLV_VAR_TYPE_MOVIE_CLIP = 4,// struct flv_script_string
    EFLV_VAR_TYPE_NULL = 5,// 
    EFLV_VAR_TYPE_UNDEF = 6,
    EFLV_VAR_TYPE_REF = 7,// uint16_t
    EFLV_VAR_TYPE_ECMA_ARRAY = 8, // SCRIPTDATAVARIABLE[ECMAArrayLength]
    EFLV_VAR_TYPE_STRICT_ARRAY = 10,// SCRIPTDATAVARIABLE[n]
    EFLV_VAR_TYPE_DATE = 11,// SCRIPTDATADATE
    EFLV_VAR_TYPE_LONG_STRING = 12,// SCRIPTDATALONGSTRING
};

struct flv_script_string
{
    uint16_t len;
    uint8_t data[1024];// max 65535
};
struct flv_script_date
{
    double datatime; // Number of milliseconds since Jan 1, 1970 UTC.
    int16_t localDateTimeOffset;
};
struct flv_script_payload
{
    // TODO...
};
struct flv_script_dvalue
{
    uint8_t type;
    uint32_t ECMAArrayLength;// if type = 8
    struct flv_script_payload payload;// depends on type and ECMAArrayLength
    uint32_t endMarker:24;// always is 9
};
struct flv_script_variable
{
    struct flv_script_string name;
    struct flv_script_dvalue value;
};
struct flv_script_object
{
    struct flv_script_string name;
    struct flv_script_dvalue value;
};

struct flv_script_data
{
    struct flv_script_object objects[]; 
    uint32_t endMarker:24;// always is 9
};

union flv_tag_data
{
    struct flv_audio_data audioData;
    struct flv_video_data videoData;
    struct flv_script_data scriptData;
};

struct flv_tag
{
    struct flv_tag_header header;// size always is 11
    union flv_tag_data data; // depends on tag type
    uint32_t tagSize;// 11 + data size
};

/*
 * flv body
 */
struct flv_body
{
    uint32_t prevTagSize0; // always is 0
    struct flv_tag tag[];
};

/*
 * flv onMetaData marker
 */
struct flv_onmeta_data
{
    double duration;// seconds
    double width;
    double height;
    double videodatarate;// unit is kbps
    double framerate;
    double videocodecid; // see video tag
    double audiosamplerate;
    double audiosamplesize;
    uint8_t stereo;
    double audiocodecid;// see audio tag
    double filesize;// bytes
};

#endif

